home *** CD-ROM | disk | FTP | other *** search
- unit Patterns;
-
- interface
-
- type
-
- TPatPtr = ^TPattern;
-
- mType = record case integer of
-
- 0: (ch:char);
- 1:(str:PChar);
- 2:(cset:set of char);
- 3:(pat:TPatPtr);
- 4:(index:word);
-
- end;
-
- TPattern = record
-
- mf:function(Pat:TPatPtr):boolean;
- m:mType;
- Next:TPatPtr;
- Alt:TPatPtr;
- success:procedure(Pat:TPatPtr);
- EndPattern:PChar;
- StartPattern:PChar;
-
- end;
-
-
- function match(var Pattern:TPattern; var str:PChar):boolean;
-
- function SpanCset(Pat:TPatPtr):Boolean;
- function AnyCset(Pat:TPatPtr):Boolean;
- function OneOrMoreCset(Pat:TPatPtr):Boolean;
- function BrkCset(Pat:TPatPtr):Boolean;
- function NotAnyCset(Pat:TPatPtr):Boolean;
- function MatchStr(Pat:TPatPtr):Boolean;
- function MatchiStr(Pat:TPatPtr):Boolean;
- function MatchChar(Pat:TPatPtr):Boolean;
- function MatchChars(Pat:TPatPtr):Boolean;
- function MatchToChar(Pat:TPatPtr):Boolean;
- function MatchToPat(Pat:TPatPtr):Boolean;
- function ARB(Pat:TPatPtr):Boolean;
- function ARBNUM(Pat:TPatPtr):Boolean;
- function EOS(Pat:TPatPtr):Boolean;
- function skip(Pat:TPatPtr):Boolean;
- function pos(Pat:TPatPtr):Boolean;
- function MatchSub(Pat:TPatPtr):Boolean;
- function Succeed(Pat:TPatPtr):Boolean;
-
-
- implementation
-
- uses SysUtils;
-
- function match(var Pattern:TPattern; var str:PChar):boolean;
- begin
-
- Pattern.StartPattern := str;
- Pattern.EndPattern := str;
-
- { See if the current pattern matches anything at the }
- { beginning of the current string. }
-
- if (Pattern.mf(@Pattern)) then
- begin
-
- { If we got a match, see if there is a follow-on }
- { pattern and try to match it, if so; If no such }
- { pattern, return success. }
-
- if (Pattern.Next <> NIL) then
- begin
-
- Result := match(Pattern.Next^, Pattern.EndPattern);
- if Result then
- Pattern.EndPattern := Pattern.Next^.EndPattern;
-
- end
- else Result := true;
-
- { If we've got a successful match, and "success" points }
- { at a procedure, execute that procedure. }
-
- if Result and (@Pattern.Success <> NIL) then
- Pattern.Success(@Pattern);
-
- end
-
- { If the pattern did not match, look for an alternate }
- { pattern and try to match it if it exists. Return }
- { failure if there is no alternate pattern. }
-
- else if (Pattern.Alt <> NIL) then
- begin
-
- Result := match(Pattern.Alt^, Pattern.EndPattern);
- if (Result) then
- Pattern.EndPattern := Pattern.Alt^.EndPattern;
- end
- else Result := false;
-
-
- end;
-
-
- function MatchSub(Pat:TPatPtr):Boolean;
- begin
-
-
- Result := Match(Pat^.m.Pat^, Pat^.EndPattern);
- if (Result) then Pat^.EndPattern := Pat^.m.Pat^.EndPattern;
-
- end;
-
-
- { Succeed- Always Succeeds }
-
- function Succeed(Pat:TPatPtr):Boolean;
- begin
-
- Result := true;
-
- end;
- { SpanCset- This matching function skips over any characters }
- { found in the cset field. }
-
- function SpanCset(Pat:TPatPtr):Boolean;
- begin
-
- while (Pat^.EndPattern^ in Pat^.m.cset) do inc(Pat^.EndPattern);
- Result := true;
-
- end;
-
-
- { AnyCset- This matching function skips over a single character}
- { found in the cset field. }
-
- function AnyCset(Pat:TPatPtr):Boolean;
- begin
-
- Result := Pat^.EndPattern^ in Pat^.m.cset;
- if Result then inc(Pat^.EndPattern);
-
- end;
-
-
- { OneOrMoreCset- This matching function skips over any chars }
- { found in the cset field. there must be at least }
- { one character for this to succeed. }
-
- function OneOrMoreCset(Pat:TPatPtr):Boolean;
- begin
-
- Result := Pat^.EndPattern^ in Pat^.m.cset;
- if Result then
- begin
-
- inc(Pat^.EndPattern);
- while (Pat^.EndPattern^ in Pat^.m.cset) do
- inc(Pat^.EndPattern);
- end;
-
- end;
-
- { BrkCset- This matching function skips over any characters }
- { that are not in the cset field. }
-
- function BrkCset(Pat:TPatPtr):Boolean;
- begin
-
- while (Pat^.EndPattern^ <> #0) and
- not (Pat^.EndPattern^ in Pat^.m.cset) do
- inc(Pat^.EndPattern);
- Result := true;
-
- end;
-
- { NotAnyCset- This matching function skips over a single }
- { character that is not in the cset field. }
-
- function NotAnyCset(Pat:TPatPtr):Boolean;
- begin
-
- Result := (Pat^.EndPattern^ = #0) or
- not (Pat^.EndPattern^ in Pat^.m.cset);
- if (Result) then inc(Pat^.EndPattern);
-
- end;
-
- { MatchStr- Skips over the characters that match a string. }
-
- function MatchStr(Pat:TPatPtr):Boolean;
-
- function MatchPrefix(var s:PChar; t:PChar):Boolean;
- var tmp:PChar;
- begin
-
- tmp := s;
- while (tmp^ = t^) and (t^ <> #0) do
- begin
-
- inc(tmp);
- inc(t);
-
- end;
- Result := t^ = #0;
- if (Result) then s := tmp;
-
- end;
-
- begin
-
- Result :=MatchPrefix(Pat^.EndPattern, Pat^.m.str);
-
- end;
-
-
- { MatchiStr- Skips over the characters that match a string, }
- { ignoring case. }
-
- function MatchiStr(Pat:TPatPtr):Boolean;
-
- function MatchPrefix(var s:PChar; t:PChar):Boolean;
- var tmp:PChar;
- begin
-
- tmp := s;
- while (upcase(tmp^) = upcase(t^)) and (t^ <> #0) do
- begin
-
- inc(tmp);
- inc(t);
-
- end;
- Result := t^ = #0;
- if (Result) then s := tmp;
-
- end;
-
- begin
-
- Result :=MatchPrefix(Pat^.EndPattern, Pat^.m.str);
-
- end;
-
-
- { MatchToStr- This function scans through the string to see }
- { if it can match some string at the current }
- { character or later in the string. }
- { This is a truly disgusting algorithm. }
- { Need to clean this one up some day. }
-
- function MatchToStr(Pat:TPatPtr):Boolean;
- var tmp:PChar;
- begin
-
- with Pat^ do
- begin
-
- tmp := EndPattern;
- while (EndPattern^ <> #0) and
- not MatchStr(Pat) do inc(EndPattern);
-
- Result := EndPattern^ <> #0;
- if not Result then EndPattern := tmp;
-
- end;
-
- end;
-
-
-
- { MatchChar- Matches a single character in the string. }
-
- function MatchChar(Pat:TPatPtr):Boolean;
- begin
-
- Result := Pat^.EndPattern^ = Pat^.m.ch;
- if Result then inc(Pat^.EndPattern);
-
- end;
-
- { MatchChars- Matches zero or more occurrences of a char- }
- { acter in the string. }
-
- function MatchChars(Pat:TPatPtr):Boolean;
- begin
-
- while (Pat^.EndPattern^ = Pat^.m.ch) do inc(Pat^.EndPattern);
- Result := true;
-
- end;
-
-
- { MatchToChar- Matches all characters in a string up to a }
- { specified character. Fails if that character }
- { is not in the string. }
-
- function MatchToChar(Pat:TPatPtr):Boolean;
- var tmp:PChar;
- begin
-
- tmp := Pat^.EndPattern;
- while (tmp^ <> #0) and (tmp^ <> Pat^.m.ch) do
- inc (tmp);
-
- Result := tmp^ = Pat^.m.ch;
- if (Result) then Pat^.EndPattern := tmp;
-
- end;
-
-
-
- { MatchToPat- Matches all characters in a string up to a }
- { specified pattern. This algorithm is a "shy" }
- { algorithm insofar is it will match as few chars }
- { as possible before matching the pattern. }
- { Also see ARB. }
-
- function MatchToPat(Pat:TPatPtr):Boolean;
- var tmp:PChar;
- begin
-
- tmp := Pat^.EndPattern;
- repeat
-
- Result := match(Pat^.m.pat^, tmp);
- if (not Result and (tmp^ <> #0)) then inc(tmp);
-
- until Result or (tmp^ = #0);
- if (Result) then Pat^.EndPattern := tmp;
-
- end;
-
-
- { ARB- Matches all characters in a string up to a }
- { specified pattern. This algorithm is a greedy }
- { algorithm insofar is it will match as many chars}
- { as possible before matching the pattern. }
- { Also see MatchToPat. }
-
- function ARB(Pat:TPatPtr):Boolean;
- var tmp:PChar;
- begin
-
- tmp := Pat^.EndPattern;
- tmp := tmp + strlen(tmp);
- repeat
-
- Result := match(Pat^.m.pat^, tmp);
- if (not Result and (tmp <> Pat^.EndPattern)) then dec(tmp);
-
- until Result or (tmp = Pat^.EndPattern);
- if (Result) then Pat^.EndPattern := Pat^.m.pat^.EndPattern;
-
- end;
-
-
- { ARBNUM- Matches an arbitrary number of strings matching }
- { the parameter pattern. }
-
- function ARBNUM(Pat:TPatPtr):Boolean;
- begin
-
- while (match(Pat^.m.pat^, Pat^.EndPattern)) do
- Pat^.EndPattern := Pat^.m.pat^.EndPattern;
- Result := true;
-
- end;
-
- { EOS- Matches the end of string character (#0). }
-
- function EOS(Pat:TPatPtr):Boolean;
- begin
-
- Result := Pat^.EndPattern^ = #0;
-
- end;
-
-
- { Skip- Skips over "index" characters in the string if }
- { there are that many characters left in the str. }
-
- function skip(Pat:TPatPtr):Boolean;
- var LastPosn,
- save :PChar;
- begin
-
- with Pat^ do begin
-
- save := EndPattern;
- LastPosn := EndPattern + m.index;
- while (EndPattern^ <> #0) and (EndPattern < LastPosn) do
- inc(EndPattern);
-
- Result := EndPattern^ <> #0;
- if not Result then EndPattern := save;
-
- end;
- end;
-
-
- { Pos- Returns true if the pattern matching algorithm }
- { is currently processing the character at pos- }
- { ition "index" in the string. }
-
- function pos(Pat:TPatPtr):Boolean;
- begin
-
- with Pat^ do begin
-
- Result := (EndPattern - StartPattern) = m.index;
-
- end;
- end;
-
-
-
-
-
- end.
-